package com.king.java.tools.email.impl;


import com.king.java.tools.email.EmailUtil;
import com.king.java.tools.email.entity.EmailEntity;
import com.king.java.tools.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * 描述: 邮件发送工具
 *
 * @author : sujinchen
 * @date : 2020/10/12
 */
public class GeneralEmailUtils implements EmailUtil {
    private Logger log = LoggerFactory.getLogger(GeneralEmailUtils.class);
    /**
     * 邮箱配置信息
     */
    private final GeneralEmailConfig generalEmailConfig;
    /**
     * 邮件内容实体
     */
    private final EmailEntity emailEntity;

    /**
     * 邮件会话对象
     */
    private Session session;

    /**
     * 邮件对象
     */
    private MimeMessage message;

    /**
     * 邮件传输对象
     */
    private Transport transport;

    /**
     * 初始化标志位
     */
    private boolean initFlag = false;

    /**
     * 正文关系描述
     */
    private MimeMultipart relation = new MimeMultipart();
    /**
     * 正文关系描述
     */
    private MimeMultipart context = new MimeMultipart();

    /**
     * 图片数量计数
     */
    private int imageCount = 0;


    public GeneralEmailUtils(GeneralEmailConfig generalEmailConfig, EmailEntity emailEntity) {
        this.generalEmailConfig = generalEmailConfig;
        this.emailEntity = emailEntity;
        String check = check(emailEntity, generalEmailConfig);
        if (!check.equals("ok")) {
            try {
                throw new Exception(check);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 关键参数检查
     *
     * @param entity
     * @param config
     * @return
     */
    private String check(EmailEntity entity, GeneralEmailConfig config) {
        if (StringUtils.isEmpty(entity.getTitle())) {
            return "title is empty：" + entity.getTitle();
        }
        if (StringUtils.isEmpty(config.getSenderAccount())) {
            return "senderAccount is empty：" + config.getSenderAccount();
        }
        if (StringUtils.isEmpty(config.getSenderPassword())) {
            return "senderPassword is empty：" + config.getSenderPassword();

        }
        if (entity.getRecipientAddress() == null || entity.getRecipientAddress().size() == 0) {
            return "recipientAddress is empty：" + config.getSenderPassword();
        }
        return "ok";
    }


    /**
     * 配置基本信息
     * @return
     */
    private Properties config() {
        return config(generalEmailConfig.getHost(), generalEmailConfig.getTransportProtocol(), generalEmailConfig.isAuth(), generalEmailConfig.isSSL());
    }

    private Properties config(String host, String transportProtocol, boolean auth, boolean isSSL) {
        Properties properties = new Properties();
        //设置邮箱服务器端口
        properties.setProperty("mail.smtp.port", generalEmailConfig.getPort() + "");
        //设置邮箱服务器地址
        properties.put("mail.host", host);
        //设置邮件发送协议
        properties.put("mail.transport.protocol", transportProtocol);
        //设置是否需要验证用户名密码
        properties.put("mail.smtp.auth", auth);
        if (isSSL) {
            properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            properties.setProperty("mail.smtp.socketFactory.fallback", "false");
            properties.setProperty("mail.smtp.socketFactory.port", generalEmailConfig.getPort() + "");
/*            try {
                MailSSLSocketFactory sf = new MailSSLSocketFactory();
                properties.put("mail.smtp.ssl.enable", "true");
                properties.put("mail.smtp.ssl.socketFactory", sf);
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }*/
        }
        return properties;
    }


    /**
     * 创建定义整个应用程序所需要的环境信息Session对象
     *
     * @return 定义整个程序所需环境信息，比如主机名、端口号、采用的邮件发送和接收协议
     */
    private Session getGlobalSession() {
        return getGlobalSession(generalEmailConfig.getSenderAccount(), generalEmailConfig.getSenderPassword(), generalEmailConfig.isDebug());
    }

    private Session getGlobalSession(final String senderAccount, final String senderPassword, boolean isDebug) {
        Session defaultInstance = Session.getDefaultInstance(config(), new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(senderAccount, senderPassword);
            }
        });
        defaultInstance.setDebug(isDebug);
        return defaultInstance;
    }

    /**
     * 获取发送邮件对象
     *
     * @return
     */
    private void setTransport() {
        if (session != null) {
            try {
                transport = session.getTransport();
            } catch (NoSuchProviderException e) {
                e.printStackTrace();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接邮件服务器
     *
     * @throws Exception
     */
    private boolean connect() {
        try {
            transport.connect(generalEmailConfig.getHost(), generalEmailConfig.getSenderAccount(), generalEmailConfig.getSenderPassword());
            return true;
        } catch (MessagingException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 获取默认的邮件对象，邮件对象用于指定收件人以及发送的内容
     *
     * @param session
     * @return
     */
    private MimeMessage getDefaultMimeMessage(Session session) {
        return new MimeMessage(session);
    }


    /**
     * 发送一封复杂邮件
     * @throws UnsupportedEncodingException
     * @throws MessagingException
     */
    @Override
    public String send() throws UnsupportedEncodingException, MessagingException {
        //1.获取全局Session对象
        session = getGlobalSession();
        //2.创建一封邮件
        message = getDefaultMimeMessage(session);
        //3.完善邮件
        //3.1指明邮件发件人
        setFrom(generalEmailConfig.getSenderAccount(),
                generalEmailConfig.getSenderAccount().split("@")[0],
                generalEmailConfig.getEncode());
        //3.2 指明邮件的收件人
        addRecipients(3, emailEntity.getRecipientAddress());
        //3.3 指明邮件的抄送人
        addRecipients(2, emailEntity.getCopyAddress());
        //3.4 指明邮件的密送人
        addRecipients(1, emailEntity.getSecretAddress());
        //3.5 邮件标题
        setEmailTitle(emailEntity.getTitle());
        //3.6 邮件正文 TODO
        setContent();
        //3.7 邮件发送时间
        setSendDate(emailEntity.getDate());
        //3.8 保存邮件设置
        saveChange();
        //4. 获取传输对象
        setTransport();
        //4.1 使用邮箱的用户名和授权码连上邮件服务器*
        connect();
        String result = "";
        if (emailEntity.isSend()) {
            //4.2 发送邮件
             result= doSend();
            //4.3 关闭资源
            close();
        }
        if (emailEntity.isSave()) {
            //TODO 保存邮件

        }
        return result;
    }

    /**
     * 设置邮件发件人
     *
     * @param senderAddress
     * @param personal
     * @param charset
     */
    private void setFrom(String senderAddress, String personal, String charset) {
        try {
            message.setFrom(new InternetAddress(senderAddress, personal, charset));
        } catch (MessagingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

    /**
     * 根据传入的类型添加收件人、抄送人以及密送人
     *
     * @param recipientType 收件人类型
     * @param addresses     收件人地址
     */
    private void addRecipients(int recipientType, List<String> addresses) {
        try {
            if (addresses != null) {
                for (String address :
                        addresses) {
                    if (recipientType == 1) {
                        message.addRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(address, address.split("@")[0], generalEmailConfig.getEncode()));
                    } else if (recipientType == 2) {
                        message.addRecipient(MimeMessage.RecipientType.CC, new InternetAddress(address, address.split("@")[0], generalEmailConfig.getEncode()));

                    } else {
                        message.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress(address, address.split("@")[0], generalEmailConfig.getEncode()));
                    }
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


    /**
     * 设置邮件标题
     *
     * @param title
     */
    private void setEmailTitle(String title) {
        try {
            message.setSubject(title);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置邮件正文
     */
    private void setContent() throws UnsupportedEncodingException, MessagingException {
        //获得注册表内容
        List<Integer> registry = emailEntity.getRegistry();
        if (registry == null || registry.size() == 0) {
            log.info("registry is null"+registry);
        }

        int text = 0;
        int image = 0;

        //处理文本和图片
        for (Integer type :
                registry) {
            if (type == 0) {
                addText(emailEntity.getContext().get(text++));
            } else if (type == 1) {
                addImages(emailEntity.getImages().get(image++));
            }
        }
        //文本和图片内嵌成功！
        relation.setSubType("related");
        //将拼装好的正文内容设置为主体
        MimeBodyPart contentText = new MimeBodyPart();
        contentText.setContent(relation);
        context.addBodyPart(contentText);
        List<String> accessorys = emailEntity.getAccessorys();
        if (accessorys != null) {
            addAccessory(accessorys);
        }
        message.setContent(context);

    }

    /**
     * 添加文本内容
     *
     * @param str
     */
    private void addText(String str) {
        MimeBodyPart text = new MimeBodyPart();
        try {
            text.setContent(str, "text/html;charset=UTF-8");
            relation.addBodyPart(text);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加图片内容
     *
     * @param path 传入图片地址
     * @throws MessagingException
     */
    private void addImages(String path) throws MessagingException {
        if (path == null) {
            return;
        }
        MimeBodyPart image = new MimeBodyPart();
        //读取图片资源
        image.setDataHandler(new DataHandler(new FileDataSource(path)));
        //设置图片id
        String cid = "image" + imageCount;
        image.setContentID(cid);
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("<img src='cid:"+cid+"'/>", "text/html;charset=utf-8");
        //拼装邮件正文内容
        relation.addBodyPart(image);
        relation.addBodyPart(text);
    }

    /**
     * 添加附件
     *
     * @param path
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private void addAccessory(List<String> path) throws MessagingException, UnsupportedEncodingException {
        if (path != null) {
            for (String file :
                    path) {
                MimeBodyPart accessory = new MimeBodyPart();
                //读取附件资源
                DataHandler dataHandler = new DataHandler(new FileDataSource(file));
                accessory.setDataHandler(dataHandler);
                accessory.setFileName(MimeUtility.encodeText(dataHandler.getName()));
                //拼接附件
                context.addBodyPart(accessory);
            }
        }
        //正文和附件都存在邮件中，所有类型设置为mixed
        context.setSubType("mixed");
    }

    /**
     * 邮件发送时间
     *
     * @param date
     */
    private void setSendDate(Date date) {
        try {
            message.setSentDate(date);
        } catch (MessagingException e) {
            e.printStackTrace();
        }

    }

    /**
     * 保存邮件设置
     */
    private void saveChange() {
        try {
            message.saveChanges();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


    /**
     * 邮件发发送
     */
    private String doSend() {
        String result = "";
        try {
            transport.sendMessage(message, message.getAllRecipients());
            result = "发送成功！";
        } catch (Exception e) {
            result = e.getMessage();
        }finally {
            return result;
        }
    }

    /**
     * 关闭邮件传输对象
     */
    private void close() {
        try {
            transport.close();
            initFlag = false;
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


}
